# Servidor, programat per Xavier Terradellas.

from PyQt4 import QtNetwork
from PyQt4 import QtGui 
from PyQt4 import QtCore
from PyQt4 import QtNetwork
import sys

class ServerWidget(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.currConnection = None
        self.OP_GETPROCESSLIST = 0
        self.OP_KILLANYPROCESS = 1
        self.blackList = QtCore.QStringList()
        self.enableKiller = False
        
        appIcon = QtGui.QIcon()
        appIcon.addFile(sys.path[0] + "\disconnect.png") 
        self.setWindowIcon ( appIcon );
        self.setWindowTitle("NAK - Network Application Killer ( Beta 1 )")
        #llistes de PC's i programes respectivament.
        self.lstClientList = QtGui.QListWidget()
        self.lstPrograms = QtGui.QListWidget()
        self.lstPrograms.setSortingEnabled ( True )
        self.connect(self.lstClientList, QtCore.SIGNAL("itemClicked (QListWidgetItem *)"), self.clientClicked)
        self.lstBlackList = QtGui.QListWidget()
        self.connect(self.lstPrograms, QtCore.SIGNAL("itemDoubleClicked(QListWidgetItem *)"), self.addToBlackList)
        self.connect(self.lstBlackList, QtCore.SIGNAL("itemDoubleClicked(QListWidgetItem *)"), self.removeFromBlackList)
        self.lbl = QtGui.QLabel()
        self.lbl.setText("")
        
        self.lblProcess = QtGui.QLabel()
        self.lblProcess.setText("Running applications:")
        
        self.lblToKill = QtGui.QLabel()
        self.lblToKill.setText("Applications to kill:")
        
        self.clientList = []
        self.clientProgramsList = {}
        
        icon = QtGui.QIcon()
        icon.addFile(sys.path[0] + "\disconnect.png") 
        
        iconIdentity = QtGui.QIcon()
        iconIdentity.addFile ( sys.path[0] +  "\identity.png")
        
        #Icona de guardar.
        self.cmdAllowKill = QtGui.QPushButton(self)
        self.cmdAllowKill.setIcon( QtGui.QIcon(icon))
        
        self.cmdCredits = QtGui.QPushButton(self)
        self.cmdCredits.setIcon ( QtGui.QIcon(iconIdentity ))
        
        #self.cmdAllowKill.setMinimumSize( QtCore.QSize(100,100))
        self.connect(self.cmdAllowKill, QtCore.SIGNAL("clicked()"), self.killButtonClicked)
        self.connect(self.cmdCredits, QtCore.SIGNAL("clicked()"), self.slotShowCredits)
        buttonBarLayout = QtGui.QBoxLayout (QtGui.QBoxLayout.LeftToRight)
        buttonBarLayout.addWidget (self.cmdAllowKill)
        buttonBarLayout.addSpacing(10)
        buttonBarLayout.addWidget (self.cmdCredits)
        
        mainLayout = QtGui.QBoxLayout (QtGui.QBoxLayout.TopToBottom, self )
        mainLayout.addWidget(self.lbl)
        mainLayout.addWidget(self.lstClientList)
        mainLayout.addWidget(self.lblProcess)
        mainLayout.addWidget(self.lstPrograms)
        mainLayout.addWidget(self.lblToKill)
        mainLayout.addWidget(self.lstBlackList)
        mainLayout.addItem(buttonBarLayout)
        self.setLayout( mainLayout )
        
        self.tcpServer = QtNetwork.QTcpServer(self)
        if self.tcpServer.listen( QtNetwork.QHostAddress( QtNetwork.QHostAddress.Any), 23):
            self.lbl.setText(self.tr("Waiting for connections from any ip, port: 23")
                             .arg(self.tcpServer.serverAddress().toString())
                             .arg(self.tcpServer.serverPort()))
        else:
            self.lbl.setText("Error: " + self.tcpServer.errorString())
        
        self.connect(self.tcpServer, QtCore.SIGNAL("newConnection()"), self.getNewConnection)
        
        #Obrir el fitxer i omplir la blackList.
        
        print "read file"
        
        import os.path
        fileStats = sys.path[0] + "\save.txt"
        if os.path.isfile ( fileStats ):
            fileHandle = open(sys.path[0] + "\save.txt", "r")
            fileList = fileHandle.readlines()
            for fileLine in fileList:
                str = fileLine
                str = str.replace("\n", "")
                print '>>', str
                self.lstBlackList.addItem( str )
                self.blackList.append ( str )
                
            fileHandle.close()
        
#    def __del__(self):
#        print "el fi"
        
    def closeEvent ( self, event ):
        #QWidget.close(self, destroy)
        print "destroy"
        file_object = open(sys.path[0] + "\save.txt", "w")
        i = 0
        for i in range(self.lstBlackList.count()):
            print i
            self.lstBlackList.setCurrentRow(i)
            file_object.write (self.lstBlackList.currentItem().text() + "\n")
        file_object.close()
    
    def killButtonClicked(self):
        print "Button clicked"
        icon = QtGui.QIcon()
        if self.enableKiller == True:
            self.enableKiller = False
            icon.addFile(sys.path[0] + "\disconnect.png") 
        else:
            self.enableKiller = True
            icon.addFile(sys.path[0] + "\connect.png")
        self.cmdAllowKill.setIcon(icon)
        self.cmdAllowKill.repaint()

    def slotShowCredits(self):
        print "Show credits"
        QtGui.QMessageBox.warning(self, self.tr("Credits"),
                   self.tr("NAK - Network Application Killer \n"
                      "Build with python by Xevi Terradellas (xeviterr@gmail.com)."))
        
    def clientClicked(self, itemSelected):
        print "clients IP clicked, listing programs."
        print itemSelected.text()
        self.fillLstPrograms(self.lstClientList.currentItem().text())
  
    def addToBlackList(self, itemSelected):
        print "addToBlackList"
        print itemSelected
        item = QtGui.QListWidgetItem()
        item.setText (itemSelected.text())
        self.lstBlackList.insertItem(1, item)
        
        str = QtCore.QString(itemSelected.text())
        self.blackList.append ( str )
        
    def removeFromBlackList(self, itemSelected):
        print "removeFromBlackList"
        #itemSelected = QtGui.QListWidgetItem()
        currItem = self.lstBlackList.currentRow();
        self.lstBlackList.takeItem(currItem);
        
        str = QtCore.QString(itemSelected.text())
        self.blackList.removeAll ( str )
        del ( itemSelected )
        
    def fillLstPrograms(self, idClient):
        self.lstPrograms.clear()
        j = 0
        procs = self.clientProgramsList[idClient]
        for j in range(procs.count()):
            procName = procs[j]
            
            item = QtGui.QListWidgetItem()
            item.setText (procName)
            self.lstPrograms.insertItem(j, item)
        
    def getNewConnection(self):
        print ("getNewConnection")
        self.currConnection = self.tcpServer.nextPendingConnection()
        self.connect(self.currConnection, QtCore.SIGNAL("readyRead()"), self.getNetworkData)
        self.connect(self.currConnection, QtCore.SIGNAL("disconnected()"),
                     self.currConnection, QtCore.SLOT("deleteLater()"))
        
        #Apunta a la llista si cal el nom del PC.
        if ( self.clientList.count(self.currConnection.peerAddress().toString()) == 0):
            self.clientList.append(self.currConnection.peerAddress().toString())
            item = QtGui.QListWidgetItem()
            item.setText (self.currConnection.peerAddress().toString())
            
            self.icon = QtGui.QIcon()
            self.icon.addFile ( sys.path[0] +  "\identity.png")
            item.setIcon( self.icon )
            
            self.lstClientList.insertItem(1, item)
        
        
    def getNetworkData(self):
        print ("gen networkdata reached")
        if not self.currConnection is None:
            socket = self.currConnection

            instr = QtCore.QDataStream(socket)
            instr.setVersion(QtCore.QDataStream.Qt_4_0)
            #llegim el tamany de les dades a capturar.
            x = QtCore.QString(socket.bytesAvailable())
            if not( socket.bytesAvailable() >= 2 ):
                return 
            else:
                operationvalue = instr.readUInt16()
            print ("reciving data 2")
            if ( operationvalue == self.OP_GETPROCESSLIST ):
                if not( socket.bytesAvailable() >= 2 ):
                    return 
                else:
                    numberOfProcess = instr.readUInt16()
                
                procs = QtCore.QStringList()
                i=0
                for i in range(numberOfProcess):
                    procName = QtCore.QString()
                    instr >> procName
                    procs.append ( procName )
                    print "Process: " + procName
    
                j=0
                for j in range(procs.count()):
                    print procs.count()
                    
                    procName = procs[j]
                    print "ProcName:" + procName

                    if self.blackList.contains(procName):
                        if ( self.enableKiller == True ):
                            print "send kill"
                            self.sendKillProcess(procName)
                        
                #Afegim el valor al diccionari de programes en execucio per cada ip
                self.clientProgramsList[self.currConnection.peerAddress().toString()] = procs
         
            socket.disconnectFromHost()
            socket.close()
        else:
            print ("Data error")
    
    def sendKillProcess (self, processName):
        block = QtCore.QByteArray()
        out = QtCore.QDataStream(block, QtCore.QIODevice.WriteOnly)
        out.setVersion(QtCore.QDataStream.Qt_4_0)
        out.writeUInt16(self.OP_KILLANYPROCESS)
        out << QtCore.QString(processName)
        out.device().seek(0)
       
        socket = self.currConnection
        socket.write(block)
        print ("Kill send")
        
    
